#include "epoller.h"

#inclue<string.h>
#include<sys/epoll.h>
#include<fcntl.h>

#include "channel.h"

using namespace tiny_muduo;

Epoller::Epoller()
    :epollfd_(epoll_create(kMaxEvents)),events_(kMaxEvents){
    }

void Epoller::Poll(channel& channels){
    printf("Epoller Poll start\n");
    int eventnums=Epollwait();
    FillActiveChannels(eventnums,channels);
    printf("Epoller Poll end\n");
}

void Epoller::FillActiveChannels(int eventnums,Channels& channels){
    for(int i=0;i<eventnums;i++){
        Channel* ptr=static_cast<Channel*>(events_[i].data.ptr);
        ptr->SetReceivedEvents(events_[i].events);
        channels.emplace_back(ptr);
    }
}

int Epoller::SetNonBlocking(int fd){
    int old_state=fcntl(fd,F_GETFL);//获取文件原来的状态
/*
fcntl函数的第一个参数是文件描述符，第二个参数F_GETFD：获取文件描述符标志。F_SETFD：设置文件描述符标志。
F_GETFL：获取文件状态标志。F_SETFL：设置文件状态标志
你可能会疑惑这里第一个参数不是fd吗？怎么第二个参数是F_GETFL。其实FD还是FL并不是表面上的理解，要根据具体的作用
选择，和第一个参数是啥无关，具体的作用RTFW(比如这里是获取文件状态，所以就应该用F_GETFL而不是F_GETFD)
*/
    int new_state=old_state|O_NONBLOCK;
    fcntl(fd,F_SETFL,new_state);
    return new_state;
}

void Epoller::Update(Channel* channel){
    int op=0,events=channel->events();
    if(events & EPOLLIN){ //可读状态
        op=EPOLL_CTL_ADD; //将文件描述符加入epoll
        SetNonBlocking(channel->fd());//并设置为非阻塞状态
    }else if(events&EPOLLRDHUP){//EPOLLRDHUP表示对方关闭连接或对方发送FIN信号
        op=EPOLL_CTL_DEL;
    }else{

    }
    UpdateChannel(op,channel);
}

void Epoller::UpdataChannel(int operation,Channel* channel){
    struct epoll_event event;
    memset(&event,'\0',sizeof(struct epoll_event));
    event.events=Channel->events()|EPOLLET;
    event.data.ptr=static_cast<void*>(channel);

    epoll_ctl(epollfd_,operation,channel->fd(),&event);
    return;
}